home *** CD-ROM | disk | FTP | other *** search
/ Revista do CD-ROM 97 / CD-ROM 97 / CD-ROM 97.iso / internet / ghostzilla / ghsetup.exe / chrome / comm.jar / content / communicator / sidebar / customize.js < prev    next >
Encoding:
Text File  |  2002-04-10  |  25.1 KB  |  767 lines

  1. /* -*- Mode: Java; tab-width: 4; insert-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  * The contents of this file are subject to the Netscape Public
  3.  * License Version 1.1 (the "License"); you may not use this file
  4.  * except in compliance with the License. You may obtain a copy of
  5.  * the License at http://www.mozilla.org/NPL/
  6.  *
  7.  * Software distributed under the License is distributed on an "AS
  8.  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  9.  * implied. See the License for the specific language governing
  10.  * rights and limitations under the License.
  11.  *
  12.  * The Original Code is Mozilla Communicator client code, released
  13.  * March 31, 1998.
  14.  *
  15.  * The Initial Developer of the Original Code is Netscape
  16.  * Communications Corporation. Portions created by Netscape are
  17.  * Copyright (C) 1998-1999 Netscape Communications Corporation. All
  18.  * Rights Reserved.
  19.  *
  20.  */
  21.  
  22. //////////////////////////////////////////////////////////////
  23. // Global variables
  24. //////////////////////////////////////////////////////////////
  25.  
  26. // Set to true for noise
  27. const CUST_DEBUG = false;
  28.  
  29. // the rdf service
  30. var RDF = '@mozilla.org/rdf/rdf-service;1'
  31. RDF = Components.classes[RDF].getService();
  32. RDF = RDF.QueryInterface(Components.interfaces.nsIRDFService);
  33.  
  34. var NC = "http://home.netscape.com/NC-rdf#";
  35.  
  36. var sidebarObj = new Object;
  37. var allPanelsObj = new Object;
  38. var original_panels = new Array();
  39.  
  40. //////////////////////////////////////////////////////////////
  41. // Sidebar Init/Destroy
  42. //////////////////////////////////////////////////////////////
  43.  
  44. function sidebar_customize_init()
  45. {
  46.   allPanelsObj.datasources = window.arguments[0];
  47.   allPanelsObj.resource    = window.arguments[1];
  48.   sidebarObj.datasource_uri     = window.arguments[2];
  49.   sidebarObj.resource           = window.arguments[3];
  50.  
  51.   debug("Init: all panels datasources = " + allPanelsObj.datasources);
  52.   debug("Init: all panels resource    = " + allPanelsObj.resource);
  53.   debug("Init: sidebarObj.datasource_uri = " + sidebarObj.datasource_uri);
  54.   debug("Init: sidebarObj.resource       = " + sidebarObj.resource);
  55.  
  56.   var all_panels   = document.getElementById('other-panels');
  57.   var current_panels = document.getElementById('current-panels');
  58.  
  59.   debug("Adding observer to all panels database.");
  60.   all_panels.database.AddObserver(panels_observer);
  61.  
  62.   allPanelsObj.datasources = allPanelsObj.datasources.replace(/^\s+/,'');
  63.   allPanelsObj.datasources = allPanelsObj.datasources.replace(/\s+$/,'');
  64.   allPanelsObj.datasources = allPanelsObj.datasources.split(/\s+/);
  65.   for (var ii = 0; ii < allPanelsObj.datasources.length; ii++) {
  66.     debug("Init: Adding "+allPanelsObj.datasources[ii]);
  67.  
  68.     // This will load the datasource, if it isn't already.
  69.     var datasource = RDF.GetDataSource(allPanelsObj.datasources[ii]);
  70.     all_panels.database.AddDataSource(datasource);
  71.     current_panels.database.AddDataSource(datasource);
  72.   }
  73.  
  74.   // Add the datasource for current list of panels. It selects panels out
  75.   // of the other datasources.
  76.   debug("Init: Adding current panels, "+sidebarObj.datasource_uri);
  77.   sidebarObj.datasource = RDF.GetDataSource(sidebarObj.datasource_uri);
  78.   current_panels.database.AddDataSource(sidebarObj.datasource);
  79.  
  80.   // Root the customize dialog at the correct place.
  81.   debug("Init: reset all panels ref, "+allPanelsObj.resource);
  82.   all_panels.setAttribute('ref', allPanelsObj.resource);
  83.   debug("Init: reset current panels ref, "+sidebarObj.resource);
  84.   current_panels.setAttribute('ref', sidebarObj.resource);
  85.   save_initial_panels();
  86.   enable_buttons_for_current_panels();
  87.  
  88.   var links =
  89.     all_panels.database.GetSources(RDF.GetResource(NC + "haslink"),
  90.                                    RDF.GetLiteral("true"), true);
  91.  
  92.   while (links.hasMoreElements()) {
  93.     var folder = 
  94.       links.getNext().QueryInterface(Components.interfaces.nsIRDFResource);
  95.     var folder_name = folder.Value;
  96.     debug("+++ fixing up remote container " + folder_name + "\n");
  97.     fixup_remote_container(folder_name);
  98.   }
  99.  
  100.   sizeToContent();
  101. }
  102.  
  103. // Remember the original list of panels so that
  104. // the save button can be enabled when something changes.
  105. function save_initial_panels()
  106. {
  107.   var tree = document.getElementById('current-panels');
  108.   if (!tree.view) {
  109.     setTimeout(save_initial_panels, 0);
  110.   } else {
  111.     for (var i = 0; i < tree.view.rowCount; ++i) {
  112.       var item = tree.contentView.getItemAtIndex(i);
  113.       original_panels.push(item.id);
  114.     }
  115.   }
  116. }
  117.  
  118. function sidebar_customize_destruct()
  119. {
  120.   var all_panels = document.getElementById('other-panels');
  121.   debug("Removing observer from all_panels database.");
  122.   all_panels.database.RemoveObserver(panels_observer);
  123. }
  124.  
  125.  
  126. //////////////////////////////////////////////////////////////////
  127. // Panels' RDF Datasource Observer
  128. //////////////////////////////////////////////////////////////////
  129. var panels_observer = {
  130.   onAssert : function(ds,src,prop,target) {
  131.     //debug ("observer: assert");
  132.     // "refresh" is asserted by select menu and by customize.js.
  133.     if (prop == RDF.GetResource(NC + "link")) {
  134.       setTimeout("fixup_remote_container('"+src.Value+"')",100);
  135.       //fixup_remote_container(src.Value);
  136.     }
  137.   },
  138.   onUnassert : function(ds,src,prop,target) {
  139.     //debug ("observer: unassert");
  140.   },
  141.   onChange : function(ds,src,prop,old_target,new_target) {
  142.     //debug ("observer: change");
  143.   },
  144.   onMove : function(ds,old_src,new_src,prop,target) {
  145.     //debug ("observer: move");
  146.   },
  147.   beginUpdateBatch : function(ds) {
  148.     //debug ("observer: beginUpdateBatch");
  149.   },
  150.   endUpdateBatch : function(ds) {
  151.     //debug ("observer: endUpdateBatch");
  152.   }
  153. };
  154.  
  155. function fixup_remote_container(id)
  156. {
  157.   debug('fixup_remote_container('+id+')');
  158.  
  159.   var container = document.getElementById(id);
  160.   if (container) {
  161.     container.setAttribute('container', 'true');
  162.     container.removeAttribute('open');
  163.   }
  164. }
  165.  
  166. function fixup_children(id) {
  167.   // Add container="true" on nodes with "link" attribute
  168.   var treeitem = document.getElementById(id);
  169.  
  170.   children = treeitem.childNodes.item(1).childNodes;
  171.   for (var ii=0; ii < children.length; ii++) {
  172.     var child = children.item(ii);
  173.     if (child.getAttribute('link') != '' &&
  174.         child.getAttribute('container') != 'true') {
  175.       child.setAttribute('container', 'true');
  176.       child.removeAttribute('open');
  177.     }
  178.   }
  179. }
  180.  
  181. function get_attr(registry,service,attr_name)
  182. {
  183.   var attr = registry.GetTarget(service,
  184.                                 RDF.GetResource(NC + attr_name),
  185.                                 true);
  186.   if (attr)
  187.     attr = attr.QueryInterface(Components.interfaces.nsIRDFLiteral);
  188.   if (attr)
  189.     attr = attr.Value;
  190.   return attr;
  191. }
  192.  
  193. function SelectChangeForOtherPanels(event, target)
  194. {
  195.   enable_buttons_for_other_panels();
  196. }
  197.  
  198. function ClickOnOtherPanels(event)
  199. {
  200.   var tree = document.getElementById("other-panels");
  201.   
  202.   var rowIndex = -1;
  203.   if (event.type == "click" && event.button == 0) {
  204.     var row = {}, col = {}, obj = {};
  205.     var b = tree.treeBoxObject;
  206.     b.getCellAt(event.clientX, event.clientY, row, col, obj);
  207.  
  208.     if (obj.value == "twisty" || event.detail == 2) {
  209.       rowIndex = row.value;
  210.     }
  211.   }
  212.  
  213.   if (rowIndex < 0) return;
  214.   
  215.   var treeitem = tree.contentView.getItemAtIndex(rowIndex);
  216.   var res = RDF.GetResource(treeitem.id);
  217.   
  218.   if (treeitem.getAttribute('container') == 'true') {
  219.     if (treeitem.getAttribute('open') == 'true') {
  220.       var link = treeitem.getAttribute('link');
  221.       var loaded_link = treeitem.getAttribute('loaded_link');
  222.       if (link != '' && !loaded_link) {
  223.         debug("Has remote datasource: "+link);
  224.         add_datasource_to_other_panels(link);
  225.         treeitem.setAttribute('loaded_link', 'true');
  226.       } else {
  227.         setTimeout('fixup_children("'+ treeitem.getAttribute('id') +'")', 100);
  228.       }
  229.     }
  230.   }
  231.  
  232.   // Remove the selection in the "current" panels list
  233.   var current_panels = document.getElementById('current-panels');
  234.   current_panels.treeBoxObject.selection.clearSelection();
  235.   enable_buttons_for_current_panels();
  236. }
  237.  
  238. function add_datasource_to_other_panels(link) {
  239.   // Convert the |link| attribute into a URL
  240.   var url = document.location;
  241.   debug("Current URL:  " +url);
  242.   debug("Current link: " +link);
  243.  
  244.   var uri = Components.classes['@mozilla.org/network/standard-url;1'].createInstance();
  245.   uri = uri.QueryInterface(Components.interfaces.nsIURI);
  246.   uri.spec = url;
  247.   uri = uri.resolve(link);
  248.  
  249.   debug("New URL:      " +uri);
  250.  
  251.   // Add the datasource to the tree
  252.   var all_panels = document.getElementById('other-panels');
  253.   all_panels.database.AddDataSource(RDF.GetDataSource(uri));
  254.  
  255.   // XXX This is a hack to force re-display
  256.   //all_panels.setAttribute('ref', allPanelsObj.resource);
  257. }
  258.  
  259. // Handle a selection change in the current panels.
  260. function SelectChangeForCurrentPanels() {
  261.   // Remove the selection in the available panels list
  262.   var all_panels = document.getElementById('other-panels');
  263.   all_panels.treeBoxObject.selection.clearSelection();
  264.  
  265.   enable_buttons_for_current_panels();
  266.   enable_buttons_for_other_panels();
  267. }
  268.  
  269. // Move the selected item up the the current panels list.
  270. function MoveUp() {
  271.   var tree = document.getElementById('current-panels');
  272.   if (tree.treeBoxObject.selection.count == 1) {
  273.     var index = tree.currentIndex;
  274.     var selected = tree.contentView.getItemAtIndex(index);
  275.     var before = selected.previousSibling;
  276.     if (before) {
  277.       before.parentNode.removeChild(selected);
  278.       before.parentNode.insertBefore(selected, before);
  279.       tree.treeBoxObject.selection.select(index-1);
  280.       tree.treeBoxObject.ensureRowIsVisible(index-1);
  281.     }
  282.   }
  283.   enable_buttons_for_current_panels();
  284. }
  285.  
  286. // Move the selected item down the the current panels list.
  287. function MoveDown() {
  288.   var tree = document.getElementById('current-panels');
  289.   if (tree.treeBoxObject.selection.count == 1) {
  290.     var index = tree.currentIndex;
  291.     var selected = tree.contentView.getItemAtIndex(index);
  292.     if (selected.nextSibling) {
  293.       if (selected.nextSibling.nextSibling)
  294.         selected.parentNode.insertBefore(selected, selected.nextSibling.nextSibling);
  295.       else
  296.         selected.parentNode.appendChild(selected);
  297.       tree.treeBoxObject.selection.select(index+1);
  298.       tree.treeBoxObject.ensureRowIsVisible(index+1);
  299.     }
  300.   }
  301.   enable_buttons_for_current_panels();
  302. }
  303.  
  304. function PreviewPanel()
  305. {
  306.   var tree = document.getElementById('other-panels');
  307.   var database = tree.database;
  308.   var sel = tree.treeBoxObject.selection;
  309.   var rangeCount = sel.getRangeCount();
  310.   for (var range = 0; range < rangeCount; ++range) {
  311.     var min = {}, max = {};
  312.     sel.getRangeAt(range, min, max);
  313.     for (var index = min.value; index <= max.value; ++index) {
  314.       var item = tree.contentView.getItemAtIndex(index);
  315.       var res = RDF.GetResource(item.id);
  316.  
  317.       var preview_name = get_attr(database, res, 'title');
  318.       var preview_URL  = get_attr(database, res, 'content');
  319.       if (!preview_URL || !preview_name) continue;
  320.  
  321.       window.openDialog("chrome://communicator/content/sidebar/preview.xul",
  322.                         "_blank", "chrome,resizable,close,dialog=no",
  323.                         preview_name, preview_URL);
  324.     }
  325.   }
  326. }
  327.  
  328. // Add the selected panel(s).
  329. function AddPanel()
  330. {
  331.   var added = 0;
  332.   
  333.   var tree = document.getElementById('other-panels');
  334.   var database = tree.database;
  335.   var sel = tree.treeBoxObject.selection;
  336.   var ranges = sel.getRangeCount();
  337.   for (var range = 0; range < ranges; ++range) {
  338.     var min = {}, max = {};
  339.     sel.getRangeAt(range, min, max);
  340.     for (var index = min.value; index <= max.value; ++index) {
  341.       var item = tree.contentView.getItemAtIndex(index);
  342.       if (item.getAttribute("container") != "true") {
  343.         var res = RDF.GetResource(item.id);
  344.         // Add the panel to the current list.
  345.         add_node_to_current_list(database, res);
  346.         ++added;
  347.       }
  348.     }
  349.   }
  350.  
  351.   if (added) {
  352.     // Remove the selection in the other list.
  353.     // Selection will move to "current" list.
  354.     var all_panels = document.getElementById('other-panels');
  355.     all_panels.treeBoxObject.selection.clearSelection();
  356.  
  357.     enable_buttons_for_current_panels();
  358.     enable_buttons_for_other_panels();
  359.   }
  360. }
  361.  
  362. // Copy a panel node into a database such as the current panel list.
  363. function add_node_to_current_list(registry, service)
  364. {
  365.   debug("Adding "+service.Value);
  366.  
  367.   // Copy out the attributes we want
  368.   var option_title     = get_attr(registry, service, 'title');
  369.   var option_customize = get_attr(registry, service, 'customize');
  370.   var option_content   = get_attr(registry, service, 'content');
  371.  
  372.   var tree = document.getElementById('current-panels');
  373.   var tree_root = tree.getElementsByTagName("treechildren")[1];
  374.   
  375.   // Check to see if the panel already exists...
  376.   var i = 0;
  377.   for (var treeitem = tree_root.firstChild; treeitem; treeitem = treeitem.nextSibling) {
  378.     if (treeitem.id == service.Value) {
  379.       // The panel is already in the current panel list.
  380.       // Avoid adding it twice.
  381.       tree.treeBoxObject.selection.select(i);
  382.       tree.treeBoxObject.ensureRowIsVisible(i);
  383.       return;
  384.     }
  385.     ++i;
  386.   }
  387.  
  388.   // Create a treerow for the new panel
  389.   var item = document.createElement('treeitem');
  390.   var row  = document.createElement('treerow');
  391.   var cell = document.createElement('treecell');
  392.  
  393.   // Copy over the attributes
  394.   item.setAttribute('id', service.Value);
  395.   cell.setAttribute('label', option_title);
  396.  
  397.   // Add it to the current panels tree
  398.   item.appendChild(row);
  399.   row.appendChild(cell);
  400.   tree_root.appendChild(item);
  401.   
  402.   // Select is only if the caller wants to.
  403.   var newIndex = tree_root.getElementsByTagName("treeitem").length - 1;
  404.   tree.treeBoxObject.selection.select(newIndex);
  405.   tree.treeBoxObject.ensureRowIsVisible(newIndex);
  406. }
  407.  
  408. // Remove the selected panel(s) from the current list tree.
  409. function RemovePanel()
  410. {
  411.   var tree = document.getElementById('current-panels');
  412.   var sel = tree.treeBoxObject.selection;
  413.   
  414.   var nextNode = -1;
  415.   var rangeCount = sel.getRangeCount();
  416.   for (var range = rangeCount-1; range >= 0; --range) {
  417.     var min = {}, max = {};
  418.     sel.getRangeAt(range, min, max);
  419.     for (var index = max.value; index >= min.value; --index) {
  420.       var item = tree.contentView.getItemAtIndex(index);
  421.       var nextNode = item.nextSibling ? index : -1;
  422.       item.parentNode.removeChild(item);
  423.     }
  424.   }
  425.  
  426.   if (nextNode >= 0)
  427.     sel.select(nextNode);
  428.     
  429.   enable_buttons_for_current_panels();
  430. }
  431.  
  432. // Bring up a new window with the customize url
  433. // for an individual panel.
  434. function CustomizePanel()
  435. {
  436.   var tree  = document.getElementById('current-panels');
  437.   var numSelected = tree.selectedItems.length;
  438.  
  439.   if (numSelected == 1) {
  440.     var selectedNode  = tree.selectedItems[0];
  441.     var panel_id = selectedNode.getAttribute('id');
  442.     var customize_url = selectedNode.getAttribute('customize');
  443.  
  444.     debug("url   = " + customize_url);
  445.  
  446.     if (!customize_url) return;
  447.  
  448.     window.openDialog('chrome://communicator/content/sidebar/customize-panel.xul',
  449.                       '_blank',
  450.                       'chrome,resizable,width=690,height=600,dialog=no,close',
  451.                       panel_id,
  452.                       customize_url,
  453.                       sidebarObj.datasource_uri,
  454.                       sidebarObj.resource);
  455.   }
  456. }
  457.  
  458. function BrowseMorePanels()
  459. {
  460.   var url = '';
  461.   var browser_url = "chrome://navigator/content/navigator.xul";
  462.   var locale;
  463.   try {
  464.     var prefs = Components.classes["@mozilla.org/preferences-service;1"]
  465.                           .getService(Components.interfaces.nsIPrefBranch);
  466.     url = prefs.getCharPref("sidebar.customize.more_panels.url");
  467.     var temp = prefs.getCharPref("browser.chromeURL");
  468.     if (temp) browser_url = temp;
  469.   } catch(ex) {
  470.     debug("Unable to get prefs: "+ex);
  471.   }
  472.   window.openDialog(browser_url, "_blank", "chrome,all,dialog=no", url);
  473. }
  474.  
  475. function customize_getBrowserURL()
  476. {
  477.   return url;
  478. }
  479.  
  480. // Serialize the new list of panels.
  481. function Save()
  482. {
  483.   persist_dialog_dimensions();
  484.  
  485.   var all_panels = document.getElementById('other-panels');
  486.   var current_panels = document.getElementById('current-panels');
  487.  
  488.   // See if list membership has changed
  489.   var root = current_panels.getElementsByTagName("treechildren")[1];
  490.   var panels = root.childNodes;
  491.   var list_unchanged = (panels.length == original_panels.length);
  492.   for (var i = 0; i < panels.length && list_unchanged; i++) {
  493.     if (original_panels[i] != panels[i].id)
  494.       list_unchanged = false;
  495.   }
  496.   if (list_unchanged)
  497.     return;
  498.  
  499.   // Iterate through the 'current-panels' tree to collect the panels
  500.   // that the user has chosen. We need to do this _before_ we remove
  501.   // the panels from the datasource, because the act of removing them
  502.   // from the datasource will change the tree!
  503.   panels = [];
  504.   for (var node = root.firstChild; node != null; node = node.nextSibling)
  505.     panels.push(node.id);
  506.  
  507.   // Cut off the connection between the dialog and the datasource.
  508.   // The dialog is closed at the end of this function.
  509.   // Without this, the dialog tries to update as it is being destroyed.
  510.   current_panels.setAttribute('ref', 'rdf:null');
  511.  
  512.   // Create a "container" wrapper around the current panels to
  513.   // manipulate the RDF:Seq more easily.
  514.   var panel_list = sidebarObj.datasource.GetTarget(RDF.GetResource(sidebarObj.resource), RDF.GetResource(NC+"panel-list"), true);
  515.   if (panel_list) {
  516.     panel_list.QueryInterface(Components.interfaces.nsIRDFResource);
  517.   } else {
  518.     // Datasource is busted. Start over.
  519.     debug("Sidebar datasource is busted\n");
  520.   }
  521.  
  522.   var container = Components.classes["@mozilla.org/rdf/container;1"].createInstance();
  523.   container = container.QueryInterface(Components.interfaces.nsIRDFContainer);
  524.   container.Init(sidebarObj.datasource, panel_list);
  525.  
  526.   // Remove all the current panels from the datasource.
  527.   var have_panel_attributes = [];
  528.   current_panels = container.GetElements();
  529.   while (current_panels.hasMoreElements()) {
  530.     panel = current_panels.getNext();
  531.     id = panel.QueryInterface(Components.interfaces.nsIRDFResource).Value;
  532.     if (has_element(panels, id)) {
  533.       // This panel will remain in the sidebar.
  534.       // Remove the resource, but keep all the other attributes.
  535.       // Removing it will allow it to be added in the correct order.
  536.       // Saving the attributes will preserve things such as the exclude state.
  537.       have_panel_attributes[id] = true;
  538.       container.RemoveElement(panel, false);
  539.     } else {
  540.       // Kiss it goodbye.
  541.       delete_resource_deeply(container, panel);
  542.     }
  543.   }
  544.  
  545.   // Add the new list of panels
  546.   for (var ii = 0; ii < panels.length; ++ii) {
  547.     var id = panels[ii];
  548.     var resource = RDF.GetResource(id);
  549.     if (have_panel_attributes[id]) {
  550.       container.AppendElement(resource);
  551.     } else {
  552.       copy_resource_deeply(all_panels.database, resource, container);
  553.     }
  554.   }
  555.   refresh_all_sidebars();
  556.  
  557.   // Write the modified panels out.
  558.   sidebarObj.datasource.QueryInterface(Components.interfaces.nsIRDFRemoteDataSource).Flush();
  559. }
  560.  
  561. // Search for an element in an array
  562. function has_element(array, element) {
  563.   for (var ii=0; ii < array.length; ii++) {
  564.     if (array[ii] == element) {
  565.       return true;
  566.     }
  567.   }
  568.   return false;
  569. }
  570.  
  571. // Search for targets from resource in datasource
  572. function has_targets(datasource, resource) {
  573.   var arcs = datasource.ArcLabelsOut(resource);
  574.   return arcs.hasMoreElements();
  575. }
  576.  
  577. // Use an assertion to pass a "refresh" event to all the sidebars.
  578. // They use observers to watch for this assertion (in sidebarOverlay.js).
  579. function refresh_all_sidebars() {
  580.   sidebarObj.datasource.Assert(RDF.GetResource(sidebarObj.resource),
  581.                                RDF.GetResource(NC + "refresh"),
  582.                                RDF.GetLiteral("true"),
  583.                                true);
  584.   sidebarObj.datasource.Unassert(RDF.GetResource(sidebarObj.resource),
  585.                                  RDF.GetResource(NC + "refresh"),
  586.                                  RDF.GetLiteral("true"));
  587. }
  588.  
  589. // Remove a resource and all the arcs out from it.
  590. function delete_resource_deeply(container, resource) {
  591.   var arcs = container.DataSource.ArcLabelsOut(resource);
  592.   while (arcs.hasMoreElements()) {
  593.     var arc = arcs.getNext();
  594.     var targets = container.DataSource.GetTargets(resource, arc, true);
  595.     while (targets.hasMoreElements()) {
  596.       var target = targets.getNext();
  597.       container.DataSource.Unassert(resource, arc, target, true);
  598.     }
  599.   }
  600.   container.RemoveElement(panel, false);
  601. }
  602.  
  603. // Copy a resource and all its arcs out to a new container.
  604. function copy_resource_deeply(source_datasource, resource, dest_container) {
  605.   var arcs = source_datasource.ArcLabelsOut(resource);
  606.   while (arcs.hasMoreElements()) {
  607.     var arc = arcs.getNext();
  608.     var targets = source_datasource.GetTargets(resource, arc, true);
  609.     while (targets.hasMoreElements()) {
  610.       var target = targets.getNext();
  611.       dest_container.DataSource.Assert(resource, arc, target, true);
  612.     }
  613.   }
  614.   dest_container.AppendElement(resource);
  615. }
  616.  
  617. function enable_buttons_for_other_panels()
  618. {
  619.   var add_button = document.getElementById('add_button');
  620.   var preview_button = document.getElementById('preview_button');
  621.   var all_panels = document.getElementById('other-panels');
  622.  
  623.   var sel = all_panels.treeBoxObject.selection;
  624.   var num_selected = sel ? sel.count : 0;
  625.   if (sel) {
  626.     var ranges = sel.getRangeCount();
  627.     for (var range = 0; range < ranges; ++range) {
  628.       var min = {}, max = {};
  629.       sel.getRangeAt(range, min, max);
  630.       for (var index = min; index <= max; ++index) {
  631.         var node = all_panels.contentView.getItemAtIndex(index);
  632.         if (node.getAttribute('container') != 'true') {
  633.           ++num_selected;
  634.         }
  635.       }
  636.     }
  637.   }
  638.  
  639.   if (num_selected > 0) {
  640.     add_button.removeAttribute('disabled');
  641.     preview_button.removeAttribute('disabled');
  642.   } else {
  643.     add_button.setAttribute('disabled','true');
  644.     preview_button.setAttribute('disabled','true');
  645.   }
  646. }
  647.  
  648. function enable_buttons_for_current_panels() {
  649.   var up        = document.getElementById('up');
  650.   var down      = document.getElementById('down');
  651.   var tree      = document.getElementById('current-panels');
  652.   var customize = document.getElementById('customize-button');
  653.   var remove    = document.getElementById('remove-button');
  654.  
  655.   var numSelected = tree.treeBoxObject.selection ? tree.treeBoxObject.selection.count : 0;
  656.  
  657.   var noneSelected, isFirst, isLast, selectedNode
  658.  
  659.   if (numSelected > 0) {
  660.     selectedNode = tree.contentView.getItemAtIndex(tree.currentIndex);
  661.     isFirst = selectedNode == selectedNode.parentNode.firstChild
  662.     isLast  = selectedNode == selectedNode.parentNode.lastChild
  663.   }
  664.  
  665.   // up /\ button
  666.   if (numSelected != 1 || isFirst) {
  667.     up.setAttribute('disabled', 'true');
  668.   } else {
  669.     up.removeAttribute('disabled');
  670.   }
  671.   // down \/ button
  672.   if (numSelected != 1 || isLast) {
  673.     down.setAttribute('disabled', 'true');
  674.   } else {
  675.     down.removeAttribute('disabled');
  676.   }
  677.   // "Customize..." button
  678.   var customizeURL = null;
  679.   if (numSelected == 1) {
  680.     customizeURL = selectedNode.getAttribute('customize');
  681.   }
  682.   if (customizeURL == null || customizeURL == '') {
  683.     customize.setAttribute('disabled','true');
  684.   } else {
  685.     customize.removeAttribute('disabled');
  686.   }
  687.   // "Remove" button
  688.   if (numSelected == 0) {
  689.     remove.setAttribute('disabled','true');
  690.   } else {
  691.     remove.removeAttribute('disabled');
  692.   }
  693. }
  694.  
  695. function persist_dialog_dimensions() {
  696.   // Stole this code from navigator.js to
  697.   // insure the windows dimensions are saved.
  698.  
  699.   // Get the current window position/size.
  700.   var x = window.screenX;
  701.   var y = window.screenY;
  702.   var h = window.outerHeight;
  703.   var w = window.outerWidth;
  704.  
  705.   // Store these into the window attributes (for persistence).
  706.   var win = document.getElementById( "main-window" );
  707.   win.setAttribute( "x", x );
  708.   win.setAttribute( "y", y );
  709.   win.setAttribute( "height", h );
  710.   win.setAttribute( "width", w );
  711. }
  712.  
  713. ///////////////////////////////////////////////////////////////
  714. // Handy Debug Tools
  715. //////////////////////////////////////////////////////////////
  716. var debug = null;
  717. var dump_attributes = null;
  718. var dump_tree = null;
  719. var _dump_tree_recur = null;
  720.  
  721. if (!CUST_DEBUG) {
  722.   debug = function (s) {};
  723.   dump_attributes = function (node, depth) {};
  724.   dump_tree = function (node) {};
  725.   _dump_tree_recur = function (node, depth, index) {};
  726. } else {
  727.   debug = function (s) { dump("-*- sb customize: " + s + "\n"); };
  728.  
  729.   dump_attributes = function (node, depth) {
  730.     var attributes = node.attributes;
  731.     var indent = "| | | | | | | | | | | | | | | | | | | | | | | | | | | | . ";
  732.  
  733.     if (!attributes || attributes.length == 0) {
  734.       debug(indent.substr(indent.length - depth*2) + "no attributes");
  735.     }
  736.     for (var ii=0; ii < attributes.length; ii++) {
  737.       var attr = attributes.item(ii);
  738.       debug(indent.substr(indent.length - depth*2) + attr.name +
  739.             "=" + attr.value);
  740.     }
  741.   }
  742.   dump_tree = function (node) {
  743.     _dump_tree_recur(node, 0, 0);
  744.   }
  745.   _dump_tree_recur = function (node, depth, index) {
  746.     if (!node) {
  747.       debug("dump_tree: node is null");
  748.     }
  749.     var indent = "| | | | | | | | | | | | | | | | | | | | | | | | | | | | + ";
  750.     debug(indent.substr(indent.length - depth*2) + index +
  751.           " " + node.nodeName);
  752.     if (node.nodeName != "#text") {
  753.       dump_attributes(node, depth);
  754.     }
  755.     var kids = node.childNodes;
  756.     for (var ii=0; ii < kids.length; ii++) {
  757.       _dump_tree_recur(kids[ii], depth + 1, ii);
  758.     }
  759.   }
  760. }
  761.  
  762. //////////////////////////////////////////////////////////////
  763. // Install the load/unload handlers
  764. //////////////////////////////////////////////////////////////
  765. addEventListener("load", sidebar_customize_init, false);
  766. addEventListener("unload", sidebar_customize_destruct, false);
  767.